#!/usr/bin/env bash
# Copyright (c) 2021 maminjie <canpool@163.com>
# SPDX-License-Identifier: MulanPSL-2.0

method_def rpm


usage_rpm() {
    module_usage "rpm" "RPM package tool"
}

do_rpm() {
    module_do "rpm" "$@"
}

rpm_usage_help() {
    module_usage_help rpm
}

# rpm_do_help subcmd
rpm_do_help() {
    module_do_help rpm "$1"
}

# __rpm_get_subcmd cmd
#   Get the fullname of cmd
# Returns:
#   "" or fullname
__rpm_get_subcmd() {
    local cmd=""
    case "${1}" in
        "h"|"help")
            cmd="help"
            ;;
        "d"|"diff")
            cmd="diff"
            ;;
        "c"|"cmp")
            cmd="compare"
            ;;
        "f"|"find")
            cmd="find"
            ;;
        "chd"|"child")
            cmd="child"
            ;;
        "gd"|"gendep")
            cmd="gendep"
            ;;
        "fd"|"finddep")
            cmd="finddep"
            ;;
        "sl"|"srclist")
            cmd="srclist"
            ;;
        "bu"|"backup")
            cmd="backup"
            ;;
        *)
            ;;
    esac
    echo "$cmd"
}


# rpm_name rpmpkg
rpm_name() {
    [[ -n "$1" ]] && rpm -qi $1 2>/dev/null | grep "^Name" | head -n1 | awk '{print $3}'
}

# rpm_name rpmpkg
rpm_src_name() {
    rpm -qpi "$1" 2>/dev/null | grep "^Source RPM" | cut -d ":" -f 2 | sed -r 's/-[^-]+-[^-]+$//' | sed 's/ //g'
}

rpm_usage_diff() {
printf "diff (d): Check the difference of RPM package

usage:
    ${PROG} rpm diff dir1 dir2
    ${PROG} rpm diff rpm1 rpm2
\n"
}

# __rpm_do_diff dir1 dir2
__rpm_do_diff() {
    local src_rpms=$(ls $1/*.rpm 2> /dev/null)
    local dst_rpms=$(ls $2/*.rpm 2> /dev/null)
    declare -A src_dict
    declare -A dst_dict

    for r in $src_rpms; do
        local name=$(rpm_name "$r")
        if [ -n "$name" ]; then
            dict_add src_dict "$name" "$r"
        fi
    done
    for r in $dst_rpms; do
        local name=$(rpm_name "$r")
        if [ -n "$name" ]; then
            dict_add dst_dict "$name" "$r"
        fi
    done

    local src_keys=$(dict_keys src_dict)
    local i=1
    local dcnt=0
    for k in $src_keys; do
        local srpm=$(dict_get src_dict "$k")
        local drpm=$(dict_get dst_dict "$k")
        if [ -z "$drpm" ]; then
            echo "$i) -only $srpm"
            ((dcnt++))
        else
            local res=$(rpmdiff "$srpm" "$drpm")
            if [ -z "$res" ]; then
                echo "$i) equal $srpm $drpm"
            else
                local resdiff=$(echo "$res" | grep -vE "\.{10}T")
                if [ -z "$resdiff" ]; then
                    echo "$i) equal $srpm $drpm"
                else
                    resdiff=$(echo "$res" | grep -E "^(added|removed)")
                    if [ -n "$resdiff" ]; then
                        echo "$i) diff $srpm $drpm"
                    else
                        echo "$i) ~diff $srpm $drpm"
                    fi
                    ((dcnt++))
                fi
                echo "$res"
            fi
            dict_remove dst_dict "$k"
        fi
        ((i++))
    done
    local dst_values=$(dict_values dst_dict)
    for v in $dst_values; do
        echo "$i) +only $v"
        ((dcnt++))
        ((i++))
    done
    echo ""
    echo "There are about $dcnt differences..."
}

# rpm_do_diff dir1 dir2
# rpm_do_diff rpm1 rpm2
rpm_do_diff() {
    if [ $# -ne 2 ]; then
        rpm_usage_diff; exit
    fi
    local a1="$1"
    local a2="$2"
    if [[ -f "$a1" && -f "$a2" ]]; then
        rpmdiff "$a1" "$a2"
    elif [[ -d "$a1" && -d "$a2" ]]; then
        __rpm_do_diff "$a1" "$a2"
    else
        rpm_usage_diff
    fi
}

rpm_usage_compare() {
printf "cmp (c): Compare rpms of different versions of the same software

usage:
    ${PROG} rpm cmp DIR1 DIR2
\n"
}

rpm_do_compare() {
    if [[ $# -ne 2 || ! -d "$1" || ! -d "$2" ]]; then
        rpm_usage_compare; exit
    fi
    bash ${BASH_SOURCE[0]%/*}/rpm_compare.bash $@
}

rpm_usage_find() {
printf "find (f): Find the RPM a file belongs to

usage:
    ${PROG} rpm f FILE DIR [FILTER]

params:
    FILE - file to be found
    DIR - directory of rpm
    FILTER - the filter of rpm name
\n"
}

rpm_do_find() {
    local file="$1"
    local dir="$2"
    local filter="$3"
    if [[ $# -lt 2 || ! -d "$dir" ]]; then
        rpm_usage_find; exit
    fi
    local rpms=""
    if [ -n "$filter" ]; then
        rpms=$(ls $dir/*.rpm 2>/dev/null | grep "$filter")
    else
        rpms=$(ls $dir/*.rpm 2>/dev/null)
    fi
    if [ -z "$rpms" ]; then
        echo "No rpm in \"$dir\""; exit
    fi
    for rpm in $rpms; do
        rpm -qpl $rpm 2>/dev/null | grep "$file"
        if [ $? -eq 0 ]; then
            echo "${rpm#./}"
        fi
    done
}

rpm_usage_child() {
printf "child (chd): Find the local child RPMs of soure RPM

usage:
    ${PROG} rpm chd PKGNAME [DIR]

params:
    PKGNAME - the name of source RPM
    DIR - the directory of RPM, default is current dir
\n"
}

rpm_do_child() {
    if [ $# -lt 1 ]; then
        rpm_usage_child; exit
    fi
    local pkgname="$1"
    local dir="$2"
    if [ -z "$dir" ]; then
        dir="."
    fi
    local rpms=$(ls $dir/*.rpm 2>/dev/null)
    for r in $rpms; do
        local s=$(rpm_src_name "$r")
        if [ "$s" = "$pkgname" ]; then
            echo "${r#./}"
        fi
    done
}

rpm_usage_gendep() {
printf "gendep (gd): Generate the dependencies of local RPMs

usage:
    ${PROG} rpm gd [DIR] [OUTFILE]

params:
    DIR - the directory of RPM, default is current dir
    OUTFILE - the output file, default is gendep.csv

note:
    the generate format is:
        R,sn,rn,requires,fn,<->,P,sn,rn,provides,fn
\n"
}

rpm_do_gendep() {
    local dir="$1"
    if [ -z "$dir" ]; then
        dir="."
    fi
    local o_file="$2"
    if [ -z "$o_file" ]; then
        o_file="gendep.csv"
    fi
    local p_file="tmp_provides.txt"
    local r_file="tmp_requires.txt"
    [ -e "$p_file" ] && rm -f $p_file
    [ -e "$r_file" ] && rm -f $r_file
    [ -e "$o_file" ] && rm -f $o_file
    OLD_IFS=$IFS
    IFS=$'\n'
    local rpms=$(ls $dir/*.rpm 2>/dev/null)
    if [ -z "$rpms" ]; then
        echo "No rpms in $dir"; exit
    fi
    local i=0
    local n=$(echo "$rpms" | wc -l)
    for r in $rpms; do
        local info=$(rpm -qpi "$r" 2>/dev/null | grep "^[Name|Source RPM]")
        local sn=$(echo "$info" | grep "^Source RPM" | cut -d ":" -f 2 | sed -r 's/-[^-]+-[^-]+$//' | sed 's/ //g')
        local rn=$(echo "$info" | grep "^Name" | head -n1 | awk '{print $3}')
        local fn="${r##*/}"
        local pros=$(rpm -qpP "$r" 2>/dev/null | uniq)
        for pro in $pros; do
            echo "P,$sn,$rn,$pro,$fn" >> $p_file
        done
        local reqs=$(rpm -qpR "$r" 2>/dev/null | uniq)
        for req in $reqs; do
            echo "R,$sn,$rn,$req,$fn" >> $r_file
        done
        echo -ne "\rgenerating provides/requires $((++i * 100 / n))%"
    done
    echo
    i=0
    n=$(wc -l $r_file | cut -d ' ' -f 1)
    # R,sn,rn,requires,fn,<->,P,sn,rn,provides,fn
    while read line; do
        local req=$(echo "$line" | awk -F ',' '{print $4}')
        local pros=$(grep "^P,[^,]*,[^,]*,$req," $p_file)
        if [ -z "$pros" ]; then
            echo "$line,<->,,,," >> $o_file
        else
            for pro in $pros; do
                echo "$line,<->,$pro" >> $o_file
            done
        fi
        echo -ne "\rgenerating dependencies $((++i * 100 / n))%"
    done < $r_file
    echo
    IFS=$OLD_IFS
    [ -e "$p_file" ] && rm -f $p_file
    [ -e "$r_file" ] && rm -f $r_file
}

rpm_usage_finddep() {
printf "finddep (fd): Find the provider/requirer from the file generated by gendep

usage:
    ${PROG} rpm fd p PKGNAME GENFILE
    ${PROG} rpm fd r PKGNAME GENFILE

params:
    p - Find the providers of PKGNAME, that depends on the providers
            such as:
                A <- B
                A <- C
            B, C are provider, A(PKGNAME) depends on B and C
    r - Find the requirers of PKGNAME, that is depended by the requirers
            such as:
                A -> B
                A -> C
            B, C are requirer, A(PKGNAME) is depended by B and C
    GENFILE - the file generated by gendep
\n"
}

# rpm_do_finddep p PKGNAME GENFILE
# rpm_do_finddep r PKGNAME GENFILE
rpm_do_finddep() {
    if [[ $# -lt 3 || ! -e "$3" ]]; then
        rpm_usage_finddep; exit
    fi
    local cmd="$1"
    local pkg="$2"
    local genfile="$3"
    grep "<->" $genfile &> /dev/null
    if [ $? -ne 0 ]; then
        echo "$genfile format is error"; exit
    fi
    OLD_IFS=$IFS
    IFS=$'\n'
    local deps=()
    # R,sn,rn,requires,fn,<->,P,sn,rn,provides,fn
    if [ "$cmd" == "p" ]; then
        local ret=$(grep "^R,$pkg," $genfile)
        echo "Pkg,Symbols,Providers,ProSrc"
        for i in $ret; do
            local symbol=$(echo "$i" | awk -F ',' '{print $4}')
            local propkg=$(echo "$i" | awk -F ',' '{print $9}')
            if [ -n "$propkg" ]; then
                local subpkg=$(echo "$i" | awk -F ',' '{print $3}')
                local prosrc=$(echo "$i" | awk -F ',' '{print $8}')
                echo "$subpkg,$symbol,$propkg,$prosrc"
                array_add deps "$prosrc"
            else
                echo "$subpkg,$symbol,,"
            fi
        done
    elif [ "$cmd" == "r" ]; then
        local ret=$(grep "<->,P,$pkg," $genfile)
        echo "Pkg,Symbols,Requirers,ReqSrc"
        for i in $ret; do
            local symbol=$(echo "$i" | awk -F ',' '{print $4}')
            local reqpkg=$(echo "$i" | awk -F ',' '{print $3}')
            if [ -n "$reqpkg" ]; then
                local subpkg=$(echo "$i" | awk -F ',' '{print $8}')
                local reqsrc=$(echo "$i" | awk -F ',' '{print $2}')
                echo "$subpkg,$symbol,$reqpkg,$reqsrc"
                array_add deps "$reqsrc"
            else
                echo "$subpkg,$symbol,,"
            fi
        done
    else
        echo "cmd \"$cmd\" is not supported"
    fi
    IFS=$OLD_IFS
    if [ ${#deps[@]} -ne 0 ]; then
        echo "result:"
        array_uniq deps
    fi
}

rpm_usage_srclist() {
printf "srclist (sl): list the source rpm of rpm

usage:
    ${PROG} rpm sl DIR

params:
    DIR - directory of rpm
\n"
}

rpm_do_srclist() {
    local dir="$1"
    if [[ $# -lt 1 || ! -d "$dir" ]]; then
        rpm_usage_srclist; exit
    fi
    local rpms=$(find "$dir" -name "*.rpm" 2>/dev/null)
    if [ -z "$rpms" ]; then
        echo "No rpm in \"$dir\""; exit
    fi
    for rpm in $rpms; do
        local srcrpm=$(rpm -qpi $rpm 2>/dev/null | grep "^Source RPM" | awk '{print $4}')
        if [ -z "$srcrpm" ]; then
            srcrpm=${rpm##*/}
        fi
        echo "$srcrpm"
    done | sort -u
}


rpm_usage_backup() {
printf "backup (bu): backup rpm files

usage:
    ${PROG} rpm bu [options] <args...>
\n"
}

rpm_do_backup() {
    script_do_bash "$SHCANPOOL_DIR/misc/sh/rpm_backup.sh" "$@"
}


rpm_docheck() {
    check_command "rpm"
    check_command "rpmdiff"
}
